<template>
  <div :class="`${prefixCls}-group-box`" v-if="filterGroup"
    :style="{ backgroundColor: getBackgroundColor(filterGroup) }">
    <div :class="`${prefixCls}-group-operate`">
      <template v-for="subGroup in filterGroup.Groups" :key="subGroup">
        <FilterContainer :filterGroup="subGroup" :parentGroup="filterGroup" :properties="entityProperties" />
      </template>
      <template v-for="rule in filterGroup.Rules" :key="rule">
        <ARow :class="`${prefixCls}-rule-box`">
          <Select size="small" v-model:value="rule.Field" :dropdownMatchSelectWidth="false" style="min-width: 150px"
            show-search :placeholder="t('component.adtable.search.selectColumn')" :filterOption="filterOption"
            @change="handleRulePropertiesChange(rule)">
            <SelectOption v-for="item in entityProperties" :key="item.Name" :value="item.Name" :label="item.Display">
              {{ item.Display }}
            </SelectOption>
          </Select>
          <Select size="small" style="min-width: 100px; margin-left: 5px" v-model:value="rule.Operate"
            :dropdownMatchSelectWidth="false" :placeholder="t('component.adtable.search.selectOperate')">
            <SelectOption v-for="entity in getFilterOperates(rule)" :key="entity.Operate" :value="entity.Operate"
              :label="entity.Display">
              {{ entity.Display }}
            </SelectOption>
          </Select>
          <div style="min-width: 200px; margin-left: 5px">
            <template v-for="entityProperty in getEntityProperties(rule)" :key="entityProperty">
              <!-- 枚举类型 -->
              <template v-if="entityProperty.ValueRange?.length > 0">
                <Select v-model:value="rule.Value" :dropdownMatchSelectWidth="false" :showSearch="true"
                  :allowClear="true" mode="SECRET_COMBOBOX_MODE_DO_NOT_USE" :filterOption="filterOption"
                  :placeholder="t('component.adtable.search.selectValue')" size="small"
                  style="width: 100%; min-width: 100%">
                  <SelectOption v-for="item in entityProperty.ValueRange" :key="item.id" :value="item.id"
                    :label="item.text">
                    {{ item.text }}
                  </SelectOption>
                </Select>
              </template>
              <!-- 非枚举类型 -->
              <template v-else>
                <!-- 布尔类型 -->
                <template v-if="['System.Boolean'].find((item) =>
    entityProperty.TypeName?.match(new RegExp(item, 'gi')),
  )
    ">
                  <Switch v-model:checked="rule.Value" size="small" />
                </template>
                <!-- 数值类型 -->
                <template v-else-if="['System.Decimal', 'System.Double'].find((item) =>
    entityProperty.TypeName?.match(new RegExp(item, 'gi')),
  )
    ">
                  <InputNumber v-model:value="rule.Value" :placeholder="t('component.adtable.search.inputNumber')"
                    size="small" style="width: 100%; min-width: 100%" />
                </template>
                <!-- 日期时间类型 -->
                <template v-else-if="['System.DateTime'].find((item) =>
    entityProperty.TypeName?.match(new RegExp(item, 'gi')),
  )
    ">
                  <DatePicker v-model:value="rule.Value" :placeholder="t('component.adtable.search.selectDateTime')"
                    size="small" style="width: 100%; min-width: 100%" />
                </template>
                <!-- Guid、整数、字符类型 -->
                <template v-else-if="[
      'System.Guid',
      'System.Int16',
      'System.Int32',
      'System.Int64',
      'System.String',
    ].find((item) => entityProperty.TypeName?.match(new RegExp(item, 'gi')))
    ">
                  <!-- 用户、组织机构、部门类型 -->
                  <template v-if="entityProperty.Flags?.length > 0">
                    <!-- 用户、组织机构、部门类型（当操作符为等于时） -->
                    <template v-if="rule.Operate === FilterOperateEnum.Equal ||
    rule.Operate === FilterOperateEnum.NotEqual
    ">
                      <Select v-model:value="rule.Value" :dropdownMatchSelectWidth="false" :showSearch="true"
                        :filterOption="filterOption" :placeholder="t('component.adtable.search.selectValue')"
                        size="small" style="width: 100%; min-width: 100%">
                        <SelectOption v-for="enumSchema in getFlagsEnumSchema(entityProperty.Flags)"
                          :key="enumSchema.key" :value="enumSchema.value" :label="enumSchema.label">
                          {{ enumSchema.label }}
                        </SelectOption>
                      </Select>
                    </template>
                    <!-- 短整数类型 -->
                    <template v-else-if="['System.Int16', 'System.Int32'].find((item) =>
    entityProperty.TypeName?.match(new RegExp(item, 'gi')),
  )
    ">
                      <InputNumber v-model:value="rule.Value" :precision="0"
                        :placeholder="t('component.adtable.search.inputInteger')" size="small"
                        style="width: 100%; min-width: 100%" />
                    </template>
                    <!-- 长整数类型 -->
                    <template v-else-if="['System.Int64'].find((item) =>
    entityProperty.TypeName?.match(new RegExp(item, 'gi')),
  )
    ">
                      <Input v-model:value="rule.Value" :placeholder="t('component.adtable.search.inputInteger')"
                        size="small" style="width: 100%; min-width: 100%"
                        onkeyup="value=value.replace(/[^{1,2,3,4,5,6,7,8,9,0}]/g,'')" />
                    </template>
                    <!-- 其他字符类型 -->
                    <template v-else>
                      <Input v-model:value="rule.Value" :placeholder="t('component.adtable.search.inputString')"
                        size="small" style="width: 100%; min-width: 100%" />
                    </template>
                  </template>
                  <!-- 短整数类型 -->
                  <template v-else-if="['System.Int16', 'System.Int32'].find((item) =>
    entityProperty.TypeName?.match(new RegExp(item, 'gi')),
  )
    ">
                    <InputNumber v-model:value="rule.Value" :precision="0"
                      :placeholder="t('component.adtable.search.inputInteger')" size="small"
                      style="width: 100%; min-width: 100%" />
                  </template>
                  <!-- 长整数类型 -->
                  <template v-else-if="['System.Int64'].find((item) =>
    entityProperty.TypeName?.match(new RegExp(item, 'gi')),
  )
    ">
                    <Input v-model:value="rule.Value" :placeholder="t('component.adtable.search.inputInteger')"
                      size="small" style="width: 100%; min-width: 100%"
                      onkeyup="value=value.replace(/[^{1,2,3,4,5,6,7,8,9,0}]/g,'')" />
                  </template>
                  <!-- 其他字符类型 -->
                  <template v-else>
                    <Input v-model:value="rule.Value" :placeholder="t('component.adtable.search.inputString')"
                      size="small" style="width: 100%; min-width: 100%" />
                  </template>
                </template>
                <!-- 其他类型 -->
                <template v-else>
                  <Input v-model:value="rule.Value" :placeholder="t('component.adtable.search.inputString')"
                    size="small" style="width: 100%; min-width: 100%" />
                </template>
              </template>
            </template>
          </div>
          <Tooltip :title="t('component.adtable.search.removeRule')" placement="top">
            <Button size="small" style="margin-left: 5px" shape="circle" @click="handleRemoveRule(rule, filterGroup)">
              <Icon icon="ant-design:close-outlined" />
            </Button>
          </Tooltip>
        </ARow>
      </template>

      <Select :value="filterGroup.Operate" size="small" :dropdownMatchSelectWidth="false"
        @change="(value) => changeGroupOperate(value, filterGroup)">
        <SelectOption v-for="entity in groupOperateEntities" :key="entity.Operate" :value="entity.Operate"
          :label="entity.Display">
          {{ entity.Display }}
        </SelectOption>
      </Select>
      <Button size="small" style="margin-left: 5px" @click="handleAddGroup(filterGroup)">
        <Icon icon="bx:bx-add-to-queue" />{{ t('component.adtable.search.addGroup') }}
      </Button>
      <Button size="small" style="margin-left: 5px" @click="handleAddRule(filterGroup)">
        <Icon icon="ic-outline-rule" />{{ t('component.adtable.search.addRule') }}
      </Button>
      <Button size="small" style="margin-left: 5px" v-if="filterGroup.Level > 1"
        @click="handleRemoveGroup(filterGroup, parentGroup)">
        <Icon icon="subway:remove-playlist" />{{ t('component.adtable.search.removeGroup') }}
      </Button>
    </div>
  </div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import { ref, watchEffect } from 'vue';
import { useDesign } from '@/hooks/web/useDesign';
import { useRootSetting } from '@/hooks/setting/useRootSetting';
import {
  Row,
  Button,
  Select,
  InputNumber,
  Input,
  Switch,
  DatePicker,
  Tooltip,
} from 'ant-design-vue';
import { isFunction } from '@/utils/is';
import { propTypes } from '@/utils/propTypes';
import Icon from '@/components/Icon/Icon.vue';

import { useI18n } from '@/hooks/web/useI18n';

import { FilterRule, FilterGroup, EnumSchema } from '@/utils/common/types';
import { getOperateEntities } from '@/utils/common';
import { FilterOperateEnum, FilterOperateEntity } from '@/enums/filterOperateEnum';
import { EntityProperty } from '@/api/model';

import { getUserFlagEnumSchema } from '@/enums/userFlagEnum';
import { getOrganizationFlagEnumSchema } from '@/enums/organizationFlagEnum';
import { getDepartmentFlagEnumSchema } from '@/enums/departmentFlagEnum';
import { EntityPropertyFlagEnum } from '@/enums/entityPropertyFlagEnum';

const ARow = Row;
const SelectOption = Select.Option;

defineOptions({ name: 'FilterContainer' });
const props = defineProps({
  /** 查询条件组 */
  filterGroup: {
    type: Object as PropType<FilterGroup>,
    default: null,
  },
  /** 父级查询条件组 */
  parentGroup: {
    type: Object as PropType<FilterGroup>,
    default: null,
  },
  /** 实体类型名称 */
  entityType: propTypes.string.def(''),
  /** 实体属性配置 */
  properties: {
    type: [Array] as PropType<EntityProperty[]>,
    default: () => [],
  },
  /** 获取实体属性配置API */
  getPropertiesApi: {
    type: Function as PropType<(typeName: string) => Promise<EntityProperty[]>>,
    default: null,
  },
});

//TODO备注：ant design vue的a-select下拉框，实现既能输入内容，也可以下拉选择的效果。
//修改mode属性：mode="SECRET_COMBOBOX_MODE_DO_NOT_USE"
const { t } = useI18n();
const { getDarkMode } = useRootSetting();
const { prefixCls } = useDesign('filter-group');

const groupOperateEntities = ref<FilterOperateEntity[]>([
  new FilterOperateEntity(FilterOperateEnum.And),
  new FilterOperateEntity(FilterOperateEnum.Or),
]);

/** 获取背景色 */
function getBackgroundColor(filterGroup: FilterGroup) {
  if (getDarkMode.value === 'dark') {
    return filterGroup.Level % 2 == 0 ? '#151515' : '#1e1e1e';
  } else {
    return filterGroup.Level % 2 == 0 ? '#eee' : '#fff';
  }
}

const entityProperties = ref<EntityProperty[]>(props.properties);

watchEffect(async () => {
  const { filterGroup, entityType, properties, getPropertiesApi } = props;
  if (filterGroup && (!filterGroup.Level || filterGroup.Level === 1)) {
    FilterGroup.Init(filterGroup);
  }
  if (getPropertiesApi && isFunction(getPropertiesApi)) {
    entityProperties.value = await getPropertiesApi(entityType);
  } else {
    entityProperties.value = properties;
  }
  if (entityProperties.value === undefined || entityProperties.value === null) {
    entityProperties.value = [];
  }
});

/** 组筛选条件值更改 */
function changeGroupOperate(value: any, group: FilterGroup) {
  group.Operate = value;
}

/** 处理条件-属性选择 */
function handleRulePropertiesChange(rule: FilterRule) {
  // console.log(rule);
  if (!rule) {
    return;
  }
  const property = getEntityProperty(rule);
  if (!property) {
    return;
  }
  const entities = getFilterOperates(rule);
  if (['System.Boolean'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))) {
    rule.Operate = entities[0]?.Operate;
    rule.Value = rule.Value === true ? true : false;
  } else if (['System.Guid'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))) {
    rule.Operate = entities[0]?.Operate;
    rule.Value = '';
  } else if (
    ['System.Int16', 'System.Int32', 'System.Int64'].find((item) =>
      property.TypeName?.match(new RegExp(item, 'gi')),
    )
  ) {
    if (property.ValueRange.length === 0) {
      // 整数类型
      rule.Operate = entities[0]?.Operate;
      rule.Value = null;
    } else {
      // 枚举类型
      rule.Operate = entities[0]?.Operate;
      rule.Value = property.ValueRange[0].id || null;
    }
  } else if (
    ['System.Decimal', 'System.Double'].find((item) =>
      property.TypeName?.match(new RegExp(item, 'gi')),
    )
  ) {
    // 数值类型
    rule.Operate = entities[0]?.Operate;
    rule.Value = null;
  } else if (
    ['System.DateTime'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))
  ) {
    rule.Operate = entities[0]?.Operate;
    rule.Value = null;
  } else if (['System.String'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))) {
    rule.Operate = FilterOperateEnum.Contains;
    rule.Value = null;
  } else {
    rule.Value = null;
  }
  if (!rule.Operate || entities.filter((m) => m.Operate === rule.Operate).length === 0) {
    rule.Operate = entities[0].Operate;
  }
}
/** 处理下拉框筛选 */
const filterOption = (input: string, option: any) => {
  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};

/** 处理增加分组 */
function handleAddGroup(group: FilterGroup) {
  const subGroup = new FilterGroup();
  subGroup.Level = group.Level + 1;
  group.Groups.push(subGroup);
}
/** 处理删除分组 */
function handleRemoveGroup(group: FilterGroup, parentGroup: FilterGroup) {
  if (parentGroup) {
    const index = parentGroup.Groups.indexOf(group);
    if (index >= 0) {
      parentGroup.Groups.splice(index, 1);
    }
  }
}

/** 处理增加条件 */
function handleAddRule(group: FilterGroup) {
  const rule = new FilterRule(undefined, null);
  if (entityProperties.value.length > 0) {
    rule.Field = entityProperties.value[0].Name;
    handleRulePropertiesChange(rule);
  }
  group.Rules.push(rule);
}
/** 处理删除条件 */
function handleRemoveRule(rule: FilterRule, group: FilterGroup) {
  // console.log('rule', rule);
  // console.log('group', group);
  if (rule) {
    const index = group.Rules.indexOf(rule);
    if (index >= 0) {
      group.Rules.splice(index, 1);
    }
  }
}

/** 获取实体属性 */
function getEntityProperty(rule: FilterRule): EntityProperty {
  const property = entityProperties.value.find((n) => n.Name === rule.Field) as EntityProperty;
  return property;
}
/** 获取实体属性集合 */
function getEntityProperties(rule: FilterRule): EntityProperty[] {
  const property = entityProperties.value.find((n) => n.Name === rule.Field) as EntityProperty;
  if (property === undefined || property === null) {
    return [];
  }
  return [property];
}
/** 获取筛选条件枚举集合 */
function getFilterOperates(rule: FilterRule): FilterOperateEntity[] {
  let entities: FilterOperateEntity[] = [];
  const property = getEntityProperty(rule);
  if (property === undefined || property === null) {
    return entities;
  }
  // property.TypeName = property.TypeName ? property.TypeName : 'System.String';
  if (['System.Boolean'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))) {
    entities = getOperateEntities([FilterOperateEnum.Equal, FilterOperateEnum.NotEqual]);
  } else if (['System.Guid'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))) {
    entities = getOperateEntities([FilterOperateEnum.Equal, FilterOperateEnum.NotEqual]);
  } else if (
    ['System.Int16', 'System.Int32', 'System.Int64'].find((item) =>
      property.TypeName?.match(new RegExp(item, 'gi')),
    )
  ) {
    if (property.ValueRange.length === 0) {
      // 整数类型
      entities = getOperateEntities([
        FilterOperateEnum.Equal,
        FilterOperateEnum.NotEqual,
        FilterOperateEnum.Less,
        FilterOperateEnum.LessOrEqual,
        FilterOperateEnum.Greater,
        FilterOperateEnum.GreaterOrEqual,
      ]);
    } else {
      // 枚举类型
      entities = getOperateEntities([FilterOperateEnum.Equal, FilterOperateEnum.NotEqual]);
    }
  } else if (
    ['System.Decimal', 'System.Double'].find((item) =>
      property.TypeName?.match(new RegExp(item, 'gi')),
    )
  ) {
    // 数值类型
    entities = getOperateEntities([
      FilterOperateEnum.Equal,
      FilterOperateEnum.NotEqual,
      FilterOperateEnum.Less,
      FilterOperateEnum.LessOrEqual,
      FilterOperateEnum.Greater,
      FilterOperateEnum.GreaterOrEqual,
    ]);
  } else if (
    ['System.DateTime'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))
  ) {
    entities = getOperateEntities([
      FilterOperateEnum.Equal,
      FilterOperateEnum.NotEqual,
      FilterOperateEnum.Less,
      FilterOperateEnum.LessOrEqual,
      FilterOperateEnum.Greater,
      FilterOperateEnum.GreaterOrEqual,
    ]);
  } else if (['System.String'].find((item) => property.TypeName?.match(new RegExp(item, 'gi')))) {
    entities = getOperateEntities([
      FilterOperateEnum.Equal,
      FilterOperateEnum.NotEqual,
      FilterOperateEnum.StartsWith,
      FilterOperateEnum.EndsWith,
      FilterOperateEnum.Contains,
      FilterOperateEnum.NotContains,
    ]);
  } else {
    entities = getOperateEntities([
      FilterOperateEnum.Equal,
      FilterOperateEnum.NotEqual,
      FilterOperateEnum.Less,
      FilterOperateEnum.LessOrEqual,
      FilterOperateEnum.Greater,
      FilterOperateEnum.GreaterOrEqual,
      FilterOperateEnum.StartsWith,
      FilterOperateEnum.EndsWith,
      FilterOperateEnum.Contains,
      FilterOperateEnum.NotContains,
    ]);
  }
  return entities;
}

/** 获取标记集合枚举架构 */
function getFlagsEnumSchema(flags: EntityPropertyFlagEnum[]) {
  let outFlags: EnumSchema[] = [];
  flags.forEach((item) => {
    switch (item) {
      case EntityPropertyFlagEnum.UserFlag:
        outFlags.push(...getUserFlagEnumSchema());
        break;
      case EntityPropertyFlagEnum.OrganizationFlag:
        outFlags.push(...getOrganizationFlagEnumSchema());
        break;
      case EntityPropertyFlagEnum.DepartmentFlag:
        outFlags.push(...getDepartmentFlagEnumSchema());
        break;
    }
  });
  return outFlags;
}
</script>
<style lang="less">
@prefix-cls: ~'@{namespace}-filter-group';

.@{prefix-cls} {
  &-group-box {
    margin: 2px;
    padding: 3px;
    border: dashed 2px #ddd;
  }

  &-group-operate {
    margin: 3px 0;
  }

  &-rule-box {
    margin: 3px;
  }
}

[data-theme='dark'] {
  .@{prefix-cls} {
    &-group-box {
      border: dashed 2px #303030;
    }
  }
}
</style>
